#include "Mage.h"

#include <iomanip>

#include "lib.h"

#include "ListeSorts.h"

#include "ATL.h"

// Utilisation de min
#include <algorithm>

#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;

const unsigned Mage::nbrCompetences = 31;

const unsigned Mage::nbrRestrictions = 19;

const unsigned Mage::ppAlloues = 40;

const vector<CompetenceClasse> Mage::Comp = list_of
  (CompetenceClasse("Abjuration"                              ,  5))
  (CompetenceClasse("Altération", "Alteration"                ,  5))
  (CompetenceClasse("Conjuration - Convocation", "Conjuration",  5))
  (CompetenceClasse("Divination"                              ,  5))
  (CompetenceClasse("Enchantement - Charme", "Enchantement"   ,  5))
  (CompetenceClasse("Illusion - Fantasme", "Illusion"         ,  5))
  (CompetenceClasse("Invocation - Evocation", "Invocation"    ,  5))
  (CompetenceClasse("Nécromancie", "Necromancie"              ,  5))
  (CompetenceClasse("Armes de roublard / prêtre"              , 10))
  (CompetenceClasse("Compétences de prêtre"                   ,  5))
  (CompetenceClasse("Compétences de combattant"               ,  5))
  (CompetenceClasse("Compétences de roublard"                 ,  5))
  (CompetenceClasse("Coriace"                                 ,  5))
  (CompetenceClasse("Dés de vie à 1d6"                        , 10))
  (CompetenceClasse("Dés de vie à 1d8"                        , 20))
  (CompetenceClasse("Détection de la magie"                   , 10))
  (CompetenceClasse("Dissipation de la magie (1x/j)"          , 10))
  (CompetenceClasse("Dissipation de la magie (3x/j)"          , 15))
  (CompetenceClasse("Durée de sorts acrue (1 école)"          , 10))
  (CompetenceClasse("Durée de sorts acrue"                    , 15))
  (CompetenceClasse("Incantation rapide"                      ,  5))
  (CompetenceClasse("Lecture de la magie"                     , 10))
  (CompetenceClasse("Mage combattant"                         , 10))
  (CompetenceClasse("Mage en armure"                          , 15))
  (CompetenceClasse("Magicien-prêtre (maj)"                   , 15u, 100u, 1u ))
  (CompetenceClasse("Magicien-prêtre (min)"                   , 10u, 200u, 1u ))
  (CompetenceClasse("Résistance aux charmes et sommeil"       ,  5))
  (CompetenceClasse("Sélection d'armes étendue"               , 15))
  (CompetenceClasse("Sélection d'armes de prêtres"            , 10))
  (CompetenceClasse("Sélection d'armes de voleurs"            , 10))
  (CompetenceClasse("Sort automatique"                        ,  5))
  (CompetenceClasse("Spécialisation"                          , 15))
  (CompetenceClasse("Talents de voleur"                       ,  5u, 300u, 2u ));

const vector<CompetenceClasse> Mage::Restric = list_of
  (CompetenceClasse("Choix des armes restreint (déf ok)"          ,  3))
  (CompetenceClasse("Choix des armes restreint"                   ,  5))
  (CompetenceClasse("Comportement / tabou"                        ,  2))
  (CompetenceClasse("Cond. extérieures quotidiennes"              , 20))
  (CompetenceClasse("Cond. extérieures communes"                  , 15))
  (CompetenceClasse("Cond. extérieures rares"                     , 10))
  (CompetenceClasse("Cond. extérieures spécifiques"               ,  5))
  (CompetenceClasse("Dés de vie à 1d3"                            , 10))
  (CompetenceClasse("Difficultés de mémorisation"                 ,  5))
  (CompetenceClasse("Lim : potions, huiles et parchemins"         ,  5))
  (CompetenceClasse("Lim : anneau, de bâton, bâtonnet et baguette",  5))
  (CompetenceClasse("Lim : armes et armures magiques"             ,  5))
  (CompetenceClasse("Manque de discrétion"                        ,  5))
  (CompetenceClasse("Nombre de sorts réduit"                      ,  7))
  (CompetenceClasse("Progression ralentie"                        , 15))
  (CompetenceClasse("Sorts dangereux"                             , 10))
  (CompetenceClasse("Talisman"                                    ,  8))
  (CompetenceClasse("Temps d'incantation alongé (+3)"             ,  2))
  (CompetenceClasse("Temps d'incantation alongé (unité)"          ,  5));

//
// Pour les talents de voleur, il faut utiliser la Table 19 de la 
// page 630 du gros pdf.
//

const vector< CompetenceClasse > Mage::Spheres = list_of
  (CompetenceClasse("Générale"   , "Generale", 0 ))
  (CompetenceClasse("Animale"     ))
  (CompetenceClasse("Astrale"     ))
  (CompetenceClasse("Chaos"       ))
  (CompetenceClasse("Charme"      ))
  (CompetenceClasse("Climat"      ))
  (CompetenceClasse("Combat"      ))
  (CompetenceClasse("Conjuration" ))
  (CompetenceClasse("Création"   , "Creation", 0 ))
  (CompetenceClasse("Divination"  ))
  (CompetenceClasse("Air"         ))
  (CompetenceClasse("Eau"         ))
  (CompetenceClasse("Feu"         ))
  (CompetenceClasse("Terre"       ))
  (CompetenceClasse("Garde"       ))
  (CompetenceClasse("Guerre"      ))
  (CompetenceClasse("Loi"         ))
  (CompetenceClasse("Nécromancie", "Necromancie", 0 ))
  (CompetenceClasse("Nombres"     ))
  (CompetenceClasse("Pensée"     , "Pensee", 0 ))
  (CompetenceClasse("Protection"  ))
  (CompetenceClasse("Soin"        ))
  (CompetenceClasse("Soleil"      ))
  (CompetenceClasse("Temps"       ))
  (CompetenceClasse("Végétale"   , "Vegetale", 0 ))
  (CompetenceClasse("Vigilance"   ))
  (CompetenceClasse("Voyageur"    ));

const vector< CompetenceClasse > Mage::TalVol = list_of
  (CompetenceClasse("Attaque sournoise"                 ,  5, Basique))
  (CompetenceClasse("Corruption"                        ,  5, Pourcentage))
  (CompetenceClasse("Crocheter les serrures"            ,  5, Pourcentage))
  (CompetenceClasse("Déplacement silencieux"            ,  5, Pourcentage))
  (CompetenceClasse("Détection des bruits"              ,  5, Pourcentage))
  (CompetenceClasse("Détection de la magie"             ,  5, Pourcentage))
  (CompetenceClasse("Détection des illusions"           ,  5, Pourcentage))
  (CompetenceClasse("Esquive"                           ,  5))
  (CompetenceClasse("Evasion"                           ,  5, Pourcentage))
  (CompetenceClasse("Grimper"                           ,  5, Pourcentage))
  (CompetenceClasse("Jargon des voleurs"                ,  5))
  (CompetenceClasse("Lire des langues inconnues"        ,  5, Pourcentage))
  (CompetenceClasse("Percer un tunnel"                  ,  5, Pourcentage))
  (CompetenceClasse("Se cacher dans l'ombre"            ,  5, Pourcentage))
  (CompetenceClasse("Trouver et désamorcer les pièges"  ,  5, Pourcentage))
  (CompetenceClasse("Vol à la tire"                     ,  5, Pourcentage));

const vector< Prerequis > Mage::Limites = list_of
  (Prerequis(3, 9));

const set< string > Mage::RacesAdmises = list_of
  ( "Humain" ) ( "Demi-Elfe" ) ( "Elfe" );

/** Constructeur usuel.
 * Permet la construction d'un mage de A à Z, càd on détermine ici
 * les restrictions, puis les compétences.
 *
 * @param[in] xp le nombre de pts d'expérience du Mage.
 * @param[in] trait les traits du Mage, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param[in,out] PP nombre de points de personnage (PP) à disposition
 * pour la création du Mage.
 * @param[in] race nom de la race du personnage.
 */
Mage::Mage(unsigned xp, const vector< unsigned >& trait,
	   unsigned PP, const string& race)
  : Classe( xp, Magiciens, "Mage" )
{
  //NomClasse = "Mage";
  NombrePPsAlloues = ppAlloues;
  PP += NombrePPsAlloues;

  NombreTotalCompetences  = nbrCompetences;
  NombreTotalRestrictions = nbrRestrictions;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< CompetenceClasse > >( Comp )
    ( Spheres )( TalVol );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  blank() << setfill('*') << setw(56) << '*' << endmsg;
  blank() << "Création d'un mage" << endmsg << endmsg;

  construitClasse( PP, trait, race );

  blank() << endmsg << setfill('*') << setw(56) << '*' << endmsg;
  calculNiveau();
  calculNivMag();
}

/** Constructeur simplifié.
 * Permet de construire un Mage lors de la lecture d'un ficier xml.
 *
 * @param[in] xp le nombre de pts d'expérience du Mage.
 * @param[in] trait les traits du Mage, le 7ème contient le score de
 * force exceptionnelle, fixé à 0 si non applicable.
 * @param[in] race nom de la race du personnage.
 */
Mage::Mage( unsigned xp )
  : Classe( xp, Magiciens, "Mage" )
{
  //NomClasse = "Mage";
  NombrePPsAlloues = ppAlloues;

  NombreTotalCompetences  = nbrCompetences;
  NombreTotalRestrictions = nbrRestrictions;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< CompetenceClasse > >( Comp )
    ( Spheres )( TalVol );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
  calculNivMag();
}

/** Constructeur pour le mode graphique.
 * Permet de construire une instance de Mage avec le contenu
 * minimal, le nombre de points d'expériences et les capacités étant
 * déterminées après la déclaration.
 *
 * @param[in] trait les traits du Mage, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param[in] UI contrôle, est présent pour des raisons historiques.
 * @param[in] race nom de la race du personnage.
 */
Mage::Mage( const bool& UI )
  : Classe( 1, Magiciens, "Mage" )
{
  if (!UI)
    {
      error() << "Création du personnage impossible" << endmsg;
      exit(1);
    }

  NomClasse = "Mage";
  NombrePPsAlloues = ppAlloues;

  NombreTotalCompetences  = nbrCompetences;
  NombreTotalRestrictions = nbrRestrictions;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< CompetenceClasse > >( Comp )
    ( Spheres )( TalVol );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
  calculNivMag();
}

/**
 * Constructeur de "copie", destiné à être utilisé depuis MetaClasse.
 *
 * @param[in] ptr pointeur sur un objet de type Classe (MetaClasse en
 * fait).
 */
Mage::Mage(Classe *ptr)
  : Classe( *ptr )
{
  NomClasse = "Mage";
  NombrePPsAlloues = ppAlloues;

  NombreTotalCompetences  = nbrCompetences;
  NombreTotalRestrictions = nbrRestrictions;
  NombreTotalEnsembles    = 0;
  NombreMaxCompetences    = 0;
  ListesCompetences       = list_of< vector< CompetenceClasse > >( Comp )
    ( Spheres )( TalVol );
  ListeRestrictions       = Restric;
  PrerequisClasse         = list_of< vector< Prerequis > >( Limites );
  RacesAdmisesClasse      = list_of< set< string > >( RacesAdmises );

  calculNiveau();
  calculNivMag();
}

Mage::~Mage()
{}

void Mage::calculNiveau()
{
  if (XP < 60000)
    {
      unsigned i;
      for (i = 0; i < 5; i++)
	{
	  if (XP < (unsigned) 2500 * puissance(2, i))
	    break;
	}
      Niveau = i+1;
    }
  else if (XP < 90000)
    Niveau = 7;
  else if (XP < 135000)
    Niveau = 8;
  else if (XP < 250000)
    Niveau = 9;
  else if (XP < 375000)
    Niveau = 10;
  else if (XP < 750000)
    Niveau = 11;
  else
      Niveau = (XP - 750000) / 375000 + 12;
}

// /**
//  * L'affichage des restrictions est précédé de l'affichage du numéro de
//  * cette restriction...
//  */
// void Mage::afficher_stats(ostream& os)
// {
//   os << "Mage" << endmsg;
//   for (unsigned i(0); i<6; i++)
//     os << Caracteristiques[i] << ' ' << Traits[i] << endmsg;
//   for (unsigned i(0); i < Competences.size(); i++)
//     {
//       if (Competences[i] >= nbrCompetences)
// 	{
// 	  //os << Competences[i] << endmsg;
// 	  os << Restric[Competences[i]-20].Comp << endmsg;
// 	}
//       else
// 	os << Comp[Competences[i]].Comp << endmsg;
//     }
// }

// void Mage::appliquerModif(const string& type)
// {}

// void Mage::augmenterTalents(const unsigned& bonus, const bool& lvl_up)
// {}

void Mage::js(unsigned *tab) const
{
  *(tab + 0) = 14; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 11; // Bâton, batonnet baguette
  *(tab + 2) = 13; // Pétrification ou Métamorphose
  *(tab + 3) = 15; // Souffles
  *(tab + 4) = 12; // Sorts
  
  unsigned cat;
  if (Niveau <= 5)
    cat = 0;
  else  if (Niveau <= 10)
    cat = 1;
  else  if (Niveau <= 15)
    cat = 2;
  else  if (Niveau <= 20)
    cat = 3;
  else
    cat = 4;

  *(tab + 0) -= cat;
  *(tab + 1) -= 2 * cat;
  *(tab + 2) -= 2 * cat;
  *(tab + 3) -= 2 * cat;
  *(tab + 4) -= 2 * cat;
}

// string Mage::competence(const unsigned& i) const
// {
//   /*Debug::*/empileNiveau( &elementaire );
//   //DebugLevelType etat_precedent(dout.getLevel());
//   //dout.setLevel(elementaire);
//   debug() <<  i << "-ème compétence => Compétence " << comp(i)
// 	      << endmsg;
//   if (comp(i) < nbrCompetences)
//     {
//       debug() << "=> compétence" << endmsg;
//       /*Debug::*/depileNiveau();//dout.setLevel(etat_precedent);
//       return Comp[comp(i)].Comp;
//     }
//   else
//     {
//       debug() << "=> restriction" << endmsg;
//       /*Debug::*/depileNiveau();//dout.setLevel(etat_precedent);
//       return Restric[comp(i)-nbrCompetences].Comp;
//     }
// }

unsigned Mage::calculeTAc0() const
{
  unsigned mod_niveau((Niveau - 1) / 3);

  return 20 - mod_niveau;
}

void Mage::calculNivMag()
{
  if (Niveau < 11)
    NiveauMagique = (Niveau + 1) / 2;
  else if (Niveau == 11)
    NiveauMagique = 5;
  else if (Niveau < 20)
    NiveauMagique = Niveau / 2;
  else
    NiveauMagique = 9;
}

/**
 * Il faut ici regarder dans SortsClasse pour savoir quels sont les sorts
 * contenus dans le Livre de Sorts du magicien.
 * 
 * Le tri se fait d'abord par Ecole, puis par Niveau et ensuite dans l'ordre
 * alphabétique.
 *
 * La variable Classe::fonction permet d'afficher :\n
 * - \e FUNC  début et fin de l'exécution de la méthode.\n
 * - \e DEBUG écrasement du fichier, nombre de sorts, sort courant
 */
void Mage::ecrireSorts( const string& nom_fichier, const bool& ecrase,
			const unsigned& ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Mage::ecrireSorts -> début" << endmsg;

  ofstream sortie;
  if (ecrase)
    {
      debug() << "Ecrasement du fichier " << nom_fichier << endmsg;
      sortie.open(nom_fichier.c_str());
    }
  else
    {
      sortie.open(nom_fichier.c_str(), ios::app);
      sortie << "\\newpage" << endl;
    }

  sortie << "\\section*{Livre de sorts - Mage}" << endl;

  vector< unsigned > vec;

  sortsParNiveau( vec, -1u );
    
  sortie << "\\begin{center}" << endl 
	 << "\\begin{tabular*}{10cm}{@{\\extracolsep{\\fill}} l r}"
	 << endl << "\\multicolumn{2}{c}{Nombre de sorts par jour} \\\\"
	 << "\\hline \\\\ \\vspace{1mm}" << endl;
  for (unsigned i(0); i < NiveauMagique; i++)
    sortie << "Niveau " << i+1 << " & " << vec[ i ] << " \\\\" << endl;
  sortie << "\\end{tabular*}" << endl << "\\end{center}" << endl;

  unsigned taille( nbrSortsConnus() ), i, courant(10), niv_courant(10);

  debug() << "nbr de sorts = " << taille << endmsg;

  for(i = 0; i < taille; i++)
    {
      debug() << "Sort courant " << SortsClasse[i] << endmsg;
      if (SortsClasse[i].ecole() != courant)
	{
	  courant = SortsClasse[i].ecole();
	  niv_courant = SortsClasse[i].niveau();
	  // courant garde en mémoire l'école courante
	  // niv_courant garde en mémoire le niveau courant
	  if (courant == 20)
	    sortie << "\\subsection*{Magie universelle}" << endl;
	  else
	    sortie << "\\subsection*{" << ListesCompetences[0][courant].nom()
		   << "}" << endl;
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}
      if (SortsClasse[i].niveau() != niv_courant)
	{
	  niv_courant = SortsClasse[i].niveau();
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}
      if (courant == 20)
      sortie << "\\input{../../Sorts-mage/Universelle" << "/sort_"
	     << niv_courant << "_" << SortsClasse[i].numero() << ".inc.tex}"
	     << endl;
      else
	sortie << "\\input{../../Sorts-mage/"
	       << ListesCompetences[0][courant].aliasNom() << "/sort_"
	       << niv_courant << "_" << SortsClasse[i].numero()
	       << ".inc.tex}" << endl;
    }

  // Il faut ajouter encore l'éventuelle sphère de mage.
  vector< unsigned >::const_iterator Maj, Min,
    Debut( Competences.begin() ), Fin( Competences.end() );
  Min = find( Debut, Fin, 25 );
  Maj = find( Debut, Fin, 24 );
  // Min et Maj sont utilisés pour savoir quelle est la sphère, en faisant ++
  // on tombe dessus
  CompetenceClasse sphere;
  
  if ( Maj != Fin )
    {
      sphere = competenceNumero( *(++Maj) );
      // Alors on a une sphère majeure
      for ( i = 0; i < NiveauMagique; i++ )
	{
	  sortie << "\\input{../../Sorts-clerc/"
		 << sphere . aliasNom()
		 << "-"  << ecrireString(i) << ".inc.tex}" << endl;
	}
    }
  else if ( Min != Fin )
    {
      sphere = competenceNumero( *(++Maj) );
      // Alors on a une sphère mineure
      for ( i = 0; i < min( NiveauMagique, 3u ); i++ )
	{
	  sortie << "\\input{../../Sorts-clerc/"
		 << sphere . aliasNom()
		 << "-"  << ecrireString(i) << ".inc.tex}" << endl;
	}
    }

  sortie.close();
  func() << "Mage::ecrireSorts -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

void Mage::sortsParNiveau( vector< unsigned >& sorts,
			   const unsigned& ) const
{
  /*Debug::*/empileNiveau( &fonction );

  func() << "Mage::nbrSort -> début" << endmsg;
  vector< unsigned > tmp( 9, 0 );
  func() << "Niveau de magie = " << NiveauMagique << endmsg;

  switch(Niveau)
    {
    case 1:
      tmp[0] = 1;
      break;
    case 2:
      tmp[0] = 2;
      break;
    case 3:
      tmp[0] = 2;
      tmp[1] = 1;
      break;
    case 4:
      tmp[0] = 3;
      tmp[1] = 2;
      break;
    case 5:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 1;
      break;
    case 6:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 2;
      break;
    case 7:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 2;
      tmp[3] = 1;
      break;
    case 8:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      break;
    case 9:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 1;
      break;
    case 10:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 2;
      break;
    case 11:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 3;
      tmp[4] = 3;
      break;
    case 12:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 1;
      break;
    case 13:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      break;
    case 14:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 15:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 16:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 2;
      tmp[7] = 1;
      break;
    case 17:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      break;
    case 18:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      tmp[8] = 1;
      break;
    case 19:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 1;
      break;
    default:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 4;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 2;
      break;
    }

  sorts.assign( tmp.begin(), tmp.end() );
  sorts.resize( NiveauMagique );

  func() << "Mage::nbrSort -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 *
 * Permet de gérer l'ajout de sorts au livre du magicien
 *
 * La variable Classe::fonction permet d'afficher
 *
 * FUNC  : les messages de début - fin de la méthode
 *
 * LFUNC : les écoles auxquelles le Mage a accès
 *
 * DEBUG : numéro du dernier sort, sort écrit, sorts triés
 */
void Mage::ajoutSorts()
{
  /*Debug::*/empileNiveau( &fonction );
  //DebugLevelType etat_precedent(dout.getLevel());
  //dout.setLevel(fonction);
  func() << "Mage::ajoutSorts -> début" << endmsg;

  bool ecoles[9] = {false, false, false, false, false, false, false, false};
  unsigned taille( tailleCompetences() ), i;
  bool sauter( false );

  for (i = 0; i < taille; i++)
    {
      if (Competences[i] < 8)
	{
	  ecoles[Competences[i]] = true;
	  lfunc() << nomCompetence(i, sauter) << " oui" << endmsg;
	}
      if ( sauter )
	i++;
    }

  unsigned nbr, dernier;
  string ecole;

  // On ajoute l'école de magie universelle
  blank() << "Magie universelle" << endmsg;
  for (i = 1; i <= NiveauMagique; i++)
    {
      blank() << "Niveau " << i << " :" << endmsg;
      dernier = afficheSorts(20, i);

      debug() << "dernier = " << dernier << endmsg;

      if (dernier > 0)
	{
	  blank() << setw(2) << dernier + 1 << " Aucun" << endmsg;
	  do
	    {
	      nbr = demanderUnsignedBorne("Entrer nouveau sort : ", 1,
					    dernier + 1);
	      if (nbr != dernier + 1)
		{
		  debug() << "Ajout du sort " << Sort(20, i, nbr - 1)
			      << endmsg;
		  SortsClasse.push_back(Sort(20, i, nbr - 1));
		}
	    }
	  while(nbr != dernier + 1);
	}
    }

  for (i = 0; i < 8; i++)
    {
      if (!ecoles[i])
	continue;
      blank() << nomCompetence(i, sauter) << endmsg;
      for (unsigned j(1); j <= NiveauMagique; j++)
	{
	  blank() << "Niveau " << j << " :" << endmsg;
	  dernier = afficheSorts(i, j);

	  debug() << "dernier = " << dernier << endmsg;
	
	  if (dernier > 0)
	    {
	      blank() << setw(2) << dernier + 1 << " Aucun" << endmsg;
	      do
		{
		  nbr = demanderUnsignedBorne("Entrer nouveau sort : ", 1,
						dernier + 1);
		  if (nbr != dernier + 1)
		    {
		      debug() << "Ajout du sort " << Sort(i, j, nbr - 1)
				  << endmsg;
		      SortsClasse.push_back(Sort(i, j, nbr - 1));
		    }
		}
	      while(nbr != dernier + 1);
	    }
	}
    }

  vector<Sort>::iterator Begin, End, it;
  Begin = SortsClasse.begin();
  End   = SortsClasse.end();

  for (i = 0; i < SortsClasse.size(); i++)
    debug() << SortsClasse[i] << endmsg;

  debug() << "Tri effectué" << endmsg;

  sort(Begin, End);

  it = unique( Begin, End );

  SortsClasse.erase( it, End );

  for (i = 0; i < SortsClasse.size(); i++)
    debug() << SortsClasse[i] << endmsg;

  func() << "Mage::ajoutSorts -> fin" << endmsg;
  /*Debug::*/depileNiveau();//dout.setLevel(etat_precedent);
}

/**
 * Permet de gérer les compétences martiales, càd lesquelles sont
 * accessibles à quel coût.
 *
 * Un Mage peut prendre un arme réservée au Mage pour 3 pp, ou une
 * arme de Clerc ou de Voleur pour 5 pp et enfin une arme de Guerrier
 * pour 6 pp.
 *
 * Si le Mage a pris une compétence comme "Sélection d'armes étendue",
 * alors ces coûts sont changés automatiquement ici.
 */
void Mage::prixAcces(map<string, unsigned>*& Map) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Mage::prixAcces -> début" << endmsg;

  map<string, unsigned>::const_iterator mapIt, mapBegin(Map -> begin()),
    mapEnd(Map -> end());

  vector< unsigned >::const_iterator it, End( Competences . end() );

  unsigned prixGuerrier( 6 ), prixClerc( 5 ), prixVoleur( 5 );

  for (it = Competences . begin(); it != End; it++)
    {
      switch( *it )
	{
	case 26:
	  prixGuerrier = 3;
	  break;
	case 27:
	  prixClerc = 3;
	  break;
	case 28:
	  prixVoleur = 3;
	}
    }

  for (mapIt = mapBegin; mapIt != mapEnd; mapIt++)
      lfunc() << mapIt -> first << endmsg;

  Map -> operator[]("Mage")     = 3;
  mapIt = Map -> find("Clerc");
  if ((mapIt != mapEnd && mapIt -> second > 5) || mapIt == mapEnd)
    Map -> operator[]("Clerc")    = prixClerc;
  mapIt = Map -> find("Voleur");
  if ((mapIt != mapEnd && mapIt -> second > 5) || mapIt == mapEnd)
    Map -> operator[]("Voleur")   = prixVoleur;
  mapIt = Map -> find("Guerrier");
  if ((mapIt != mapEnd && mapIt -> second > 6) || mapIt == mapEnd)
    Map -> operator[]("Guerrier") = prixGuerrier;
  
  func() << "Mage::prixAcces -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

string Mage::scoreAdditionnel( const unsigned& i,
			       const string& nomRace,
			       const unsigned& dexterite ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Mage::scoreAdditionnel -> début" << endmsg;
  
  string resultat( "" );

  if ( i >= 200 && i < 300 )
    {
       if ( TalVol[ i - 200 ].nom() == "Attaque sournoise" )
	 {
	   switch( Niveau )
	     {
	     case 1:
	     case 2:
	     case 3:
	     case 4:
	       resultat = "dégâts x2";
	       break;
	     case 5:
	     case 6:
	     case 7:
	     case 8:
	       resultat = "dégâts x3";
	       break;
	     case 9:
	     case 10:
	     case 11:
	     case 12:
	       resultat = "dégâts x4";
	       break;
	     default:
	       resultat = "dégâts x5";
	     }
	 }
       else if ( TalVol[ i - 200 ].autreScore() == Pourcentage )
	 {
	   vector< unsigned > *ptrComp;
	   vector< int > *ptrBonus;
	   obtenirScoresBase( Niveau, ptrComp );
	   determinerScoresAjustes( nomRace, dexterite, ptrBonus );

	   // faire une map avec le matching et ensuite appliquer les
	   // ajustements de ptrBonus, et ensuite on peut écrire le tout
	 }
    }
  
  func() << "Voleur::scoreAdditionnel -> fin" << endmsg;
  /*Debug::*/depileNiveau();

  return resultat;
}

unsigned Mage::aSpecialisation() const
{
  return find( Competences.begin(), Competences.end(), 29 ) !=
    Competences.end() ? 1 : 0;
}
